﻿namespace YidanSoft.Library.EditorUtility.WinControls
{
    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Drawing;
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Windows.Forms;
    using YidanSoft.Library.EditorUtility.General;
    using YidanSoft.Library.EditorUtility.Win32;

    [ToolboxItem(false)]
    public class ComboBoxBase : ComboBox
    {
        public const int ARROW_WIDTH = 12;
        private EditCtrlHook editHook;
        private bool fireOnSelectedIndexChanged;
        internal bool forceUpdate;
        internal bool highlighted;
        private bool hooked;
        private IntPtr mouseHookHandle;
        private GCHandle mouseProcHandle;
        private bool toolBarUse;

        public ComboBoxBase()
        {
            this.mouseHookHandle = IntPtr.Zero;
            this.toolBarUse = false;
            this.hooked = false;
            this.editHook = null;
            this.forceUpdate = false;
            this.highlighted = false;
            this.fireOnSelectedIndexChanged = true;
            base.DrawMode = DrawMode.OwnerDrawFixed;
            base.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque | ControlStyles.UserPaint, true);
        }

        public ComboBoxBase(bool toolBarUse)
        {
            this.mouseHookHandle = IntPtr.Zero;
            this.toolBarUse = false;
            this.hooked = false;
            this.editHook = null;
            this.forceUpdate = false;
            this.highlighted = false;
            this.fireOnSelectedIndexChanged = true;
            this.toolBarUse = toolBarUse;
            base.DrawMode = DrawMode.OwnerDrawFixed;
            base.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
            this.Font = SystemInformation.MenuFont;
            base.TabStop = false;
        }

        private void CalculateArrowBoxCoordinates(out int left, out int top, out int width, out int height)
        {
            Rectangle clientRectangle = base.ClientRectangle;
            width = 12;
            left = (clientRectangle.Right - width) - 2;
            top = clientRectangle.Top + 2;
            height = clientRectangle.Height - 4;
        }

        private void DrawArrowGlyph(Graphics g, bool disable)
        {
            int num;
            int num2;
            int num3;
            int num4;
            this.CalculateArrowBoxCoordinates(out num, out num2, out num3, out num4);
            Point[] points = new Point[] { new Point((num + (num3 / 2)) - 2, (num2 + (num4 / 2)) - 1), new Point((num + (num3 / 2)) + 3, (num2 + (num4 / 2)) - 1), new Point(num + (num3 / 2), ((num2 + (num4 / 2)) - 1) + 3) };
            if (disable)
            {
                g.FillPolygon(new SolidBrush(SystemColors.ControlDark), points);
            }
            else
            {
                g.FillPolygon(Brushes.Black, points);
            }
        }

        internal void DrawComboBoxArrowNormal(Graphics g, bool disable)
        {
            int num;
            int num2;
            int num3;
            int num4;
            this.CalculateArrowBoxCoordinates(out num, out num2, out num3, out num4);
            Brush brush = new SolidBrush(ColorUtil.VSNetControlColor);
            if (base.Enabled)
            {
                int num5 = SystemInformation.VerticalScrollBarWidth - 12;
                g.FillRectangle(Brushes.White, new Rectangle(num - num5, num2, SystemInformation.VerticalScrollBarWidth, num4));
            }
            if (!disable)
            {
                this.DrawComboBoxArrowSelected(g, true);
                g.FillRectangle(brush, num, num2, num3, num4);
            }
            else
            {
                g.FillRectangle(brush, (int) (num - 1), (int) (num2 - 1), (int) (num3 + 2), (int) (num4 + 2));
            }
            this.DrawArrowGlyph(g, disable);
        }

        internal void DrawComboBoxArrowSelected(Graphics g, bool erase)
        {
            int num;
            int num2;
            int num3;
            int num4;
            this.CalculateArrowBoxCoordinates(out num, out num2, out num3, out num4);
            if (base.Enabled)
            {
                int num5 = SystemInformation.VerticalScrollBarWidth - 12;
                g.FillRectangle(Brushes.White, new Rectangle(num - num5, num2, SystemInformation.VerticalScrollBarWidth, num4));
            }
            if (!erase)
            {
                if (base.DroppedDown)
                {
                    Graphics graphics = base.CreateGraphics();
                    graphics.FillRectangle(new SolidBrush(ColorUtil.VSNetPressedColor), (int) (num - 1), (int) (num2 - 1), (int) (num3 + 2), (int) (num4 + 2));
                    graphics.DrawRectangle(new Pen(new SolidBrush(ColorUtil.VSNetBorderColor), 1f), (int) (num - 1), (int) (num2 - 1), (int) (num3 + 2), (int) (num4 + 3));
                    this.DrawArrowGlyph(graphics, false);
                    graphics.Dispose();
                    this.forceUpdate = true;
                    return;
                }
                g.FillRectangle(new SolidBrush(ColorUtil.VSNetSelectionColor), (int) (num - 1), (int) (num2 - 1), (int) (num3 + 2), (int) (num4 + 2));
                g.DrawRectangle(new Pen(new SolidBrush(ColorUtil.VSNetBorderColor), 1f), (int) (num - 1), (int) (num2 - 2), (int) (num3 + 2), (int) (num4 + 3));
            }
            else
            {
                g.FillRectangle(Brushes.White, (int) (num - 1), (int) (num2 - 1), (int) (num3 + 2), (int) (num4 + 2));
            }
            this.DrawArrowGlyph(g, false);
        }

        internal void DrawComboBoxBorder(Graphics g, Color color)
        {
            if (color.Equals(ColorUtil.VSNetBorderColor))
            {
                this.highlighted = true;
            }
            else
            {
                this.highlighted = false;
            }
            Pen pen = new Pen(new SolidBrush(color), 1f);
            g.DrawRectangle(pen, base.ClientRectangle.Left, base.ClientRectangle.Top, base.ClientRectangle.Width - 1, base.ClientRectangle.Height - 1);
            g.DrawRectangle(Pens.White, (int) (base.ClientRectangle.Left + 1), (int) (base.ClientRectangle.Top + 1), (int) (base.ClientRectangle.Width - SystemInformation.VerticalScrollBarWidth), (int) (base.ClientRectangle.Height - 3));
        }

        protected virtual void DrawComboBoxItem(Graphics g, Rectangle bounds, int Index, bool selected, bool editSel)
        {
            using (Brush brush = new SolidBrush(SystemColors.Window))
            {
                g.FillRectangle(brush, bounds.Left, bounds.Top, bounds.Width, bounds.Height);
            }
            if (!(!selected || editSel))
            {
                Pen pen = new Pen(ColorUtil.VSNetBorderColor);
                Brush brush2 = new SolidBrush(ColorUtil.VSNetSelectionColor);
                g.FillRectangle(brush2, bounds.Left, bounds.Top, bounds.Width, bounds.Height);
                g.DrawRectangle(pen, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1);
                pen.Dispose();
                brush2.Dispose();
            }
            else
            {
                g.FillRectangle(new SolidBrush(SystemColors.Window), bounds.Left, bounds.Top, bounds.Width, bounds.Height);
                if (editSel && base.ContainsFocus)
                {
                    Debug.WriteLine("Drawing ComboBox Arrow...");
                    this.DrawComboBoxArrowSelected(g, false);
                }
            }
        }

        protected virtual void DrawComboBoxItemEx(Graphics g, Rectangle bounds, int Index, bool selected, bool editSel)
        {
            bounds.Inflate(-3, -3);
            using (Brush brush = new SolidBrush(SystemColors.Window))
            {
                g.FillRectangle(brush, bounds.Left, bounds.Top, bounds.Width, bounds.Height);
            }
            if (!(!selected || editSel))
            {
                Pen pen = new Pen(ColorUtil.VSNetBorderColor);
                Brush brush2 = new SolidBrush(ColorUtil.VSNetSelectionColor);
                g.FillRectangle(brush2, bounds.Left, bounds.Top, bounds.Width, bounds.Height);
                g.DrawRectangle(pen, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1);
                pen.Dispose();
                brush2.Dispose();
            }
            else
            {
                g.FillRectangle(new SolidBrush(SystemColors.Window), bounds.Left, bounds.Top, bounds.Width, bounds.Height);
                if (editSel && base.ContainsFocus)
                {
                    this.DrawComboBoxArrowSelected(g, false);
                }
            }
        }

        protected virtual void DrawDisableState()
        {
            Graphics g = base.CreateGraphics();
            this.PaintComboBoxBackground(g, SystemColors.Window);
            this.DrawComboBoxBorder(g, SystemColors.ControlDark);
            this.DrawComboBoxArrowNormal(g, true);
            g.Dispose();
        }

        private void EndHook()
        {
            WindowsAPI.UnhookWindowsHookEx(this.mouseHookHandle);
            this.mouseProcHandle.Free();
            this.mouseHookHandle = IntPtr.Zero;
        }

        private void ForcePaint(ref Message m)
        {
            Graphics g = Graphics.FromHwnd(base.Handle);
            if (!base.Enabled)
            {
                this.DrawDisableState();
            }
            else
            {
                Rectangle clientRectangle = base.ClientRectangle;
                if ((this.SelectedIndex == -1) && (base.Items.Count > 0))
                {
                    this.fireOnSelectedIndexChanged = false;
                    this.SelectedIndex = 0;
                }
                this.DrawComboBoxItemEx(g, clientRectangle, this.SelectedIndex, false, true);
                if (!base.ContainsFocus)
                {
                    this.DrawComboBoxBorder(g, SystemColors.Window);
                    this.DrawComboBoxArrowNormal(g, false);
                }
                else
                {
                    this.DrawComboBoxBorder(g, ColorUtil.VSNetBorderColor);
                }
            }
        }

        internal void ForceUpdate()
        {
            using (Graphics graphics = base.CreateGraphics())
            {
                if (base.ContainsFocus)
                {
                    this.DrawComboBoxArrowSelected(graphics, false);
                }
            }
        }

        private IntPtr MouseHook(int code, IntPtr wparam, IntPtr lparam)
        {
            YidanSoft.Library.EditorUtility.Win32.MOUSEHOOKSTRUCT mousehookstruct = (YidanSoft.Library.EditorUtility.Win32.MOUSEHOOKSTRUCT) Marshal.PtrToStructure(lparam, typeof(YidanSoft.Library.EditorUtility.Win32.MOUSEHOOKSTRUCT));
            if ((((mousehookstruct.hwnd != base.Handle) && !base.DroppedDown) && ((wparam == ((IntPtr) 0x201L)) || (wparam == ((IntPtr) 0x204L)))) || (wparam == ((IntPtr) 0xa1L)))
            {
                WindowsAPI.SetFocus(IntPtr.Zero);
            }
            else if ((((mousehookstruct.hwnd != base.Handle) && !base.DroppedDown) && ((wparam == ((IntPtr) 0x202L)) || (wparam == ((IntPtr) 0x205L)))) || (wparam == ((IntPtr) 0xa2L)))
            {
                WindowsAPI.SetFocus(IntPtr.Zero);
            }
            return WindowsAPI.CallNextHookEx(this.mouseHookHandle, code, wparam, lparam);
        }

        protected override void OnDrawItem(DrawItemEventArgs e)
        {
            Graphics g = e.Graphics;
            Rectangle bounds = e.Bounds;
            bool selected = (e.State & DrawItemState.Selected) > DrawItemState.None;
            bool editSel = (e.State & DrawItemState.ComboBoxEdit) > DrawItemState.None;
            if (e.Index != -1)
            {
                this.DrawComboBoxItem(g, bounds, e.Index, selected, editSel);
            }
        }

        protected override void OnGotFocus(EventArgs e)
        {
            base.OnGotFocus(e);
            Graphics g = base.CreateGraphics();
            this.DrawComboBoxBorder(g, ColorUtil.VSNetBorderColor);
            this.DrawComboBoxArrowSelected(g, false);
            g.Dispose();
            if (!(!this.toolBarUse || this.hooked))
            {
                this.hooked = true;
                this.StartHook();
            }
        }

        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
            if (base.DropDownStyle == ComboBoxStyle.DropDown)
            {
                IntPtr dlgItem = WindowsAPI.GetDlgItem(base.Handle, 0x3e9);
                Debug.Assert(dlgItem != IntPtr.Zero, "Fail to get ComboBox's Edit Control Handle...");
                this.editHook = new EditCtrlHook(this);
                this.editHook.AssignHandle(dlgItem);
            }
        }

        protected override void OnLostFocus(EventArgs e)
        {
            base.OnLostFocus(e);
            Graphics g = base.CreateGraphics();
            this.DrawComboBoxBorder(g, SystemColors.Window);
            this.DrawComboBoxArrowNormal(g, false);
            g.Dispose();
            if (this.toolBarUse && this.hooked)
            {
                this.hooked = false;
                this.EndHook();
            }
        }

        protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);
            Graphics g = base.CreateGraphics();
            this.DrawComboBoxBorder(g, ColorUtil.VSNetBorderColor);
            this.DrawComboBoxArrowSelected(g, false);
            g.Dispose();
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            if (!base.ContainsFocus)
            {
                Graphics g = base.CreateGraphics();
                this.DrawComboBoxBorder(g, SystemColors.Window);
                this.DrawComboBoxArrowNormal(g, false);
                g.Dispose();
            }
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            base.OnPaint(pe);
            if (base.DropDownStyle != ComboBoxStyle.DropDown)
            {
                if (!base.Enabled)
                {
                    this.DrawDisableState();
                }
                else
                {
                    this.PaintComboBoxBackground(pe.Graphics, SystemColors.Window);
                    Rectangle clientRectangle = base.ClientRectangle;
                    if ((this.SelectedIndex == -1) && (base.Items.Count > 0))
                    {
                        this.fireOnSelectedIndexChanged = false;
                        this.SelectedIndex = 0;
                    }
                    this.DrawComboBoxItemEx(pe.Graphics, clientRectangle, this.SelectedIndex, false, true);
                    if (!base.ContainsFocus)
                    {
                        this.DrawComboBoxBorder(pe.Graphics, SystemColors.Window);
                        this.DrawComboBoxArrowNormal(pe.Graphics, true);
                    }
                    else
                    {
                        this.DrawComboBoxBorder(pe.Graphics, ColorUtil.VSNetBorderColor);
                    }
                }
            }
        }

        protected override void OnSelectedIndexChanged(EventArgs e)
        {
            if (this.fireOnSelectedIndexChanged)
            {
                base.OnSelectedIndexChanged(e);
            }
            this.fireOnSelectedIndexChanged = true;
        }

        private void PaintComboBoxBackground(Graphics g, Color backColor)
        {
            Rectangle clientRectangle = base.ClientRectangle;
            clientRectangle.Inflate(-1, -1);
            g.FillRectangle(new SolidBrush(backColor), clientRectangle);
        }

        public void SetFontHeight(int newHeight)
        {
            base.FontHeight = newHeight;
        }

        private void StartHook()
        {
            WindowsAPI.HookProc proc = new WindowsAPI.HookProc(this.MouseHook);
            this.mouseProcHandle = GCHandle.Alloc(proc);
            this.mouseHookHandle = WindowsAPI.SetWindowsHookEx(7, proc, IntPtr.Zero, WindowsAPI.GetCurrentThreadId());
            if (this.mouseHookHandle == IntPtr.Zero)
            {
                throw new SecurityException();
            }
        }

        protected override void WndProc(ref Message m)
        {
            bool flag = false;
            if (m.Msg == 15)
            {
                flag = true;
            }
            base.WndProc(ref m);
            if (flag)
            {
                this.ForcePaint(ref m);
            }
        }

        public bool ToolBarUse
        {
            get
            {
                return this.toolBarUse;
            }
            set
            {
                this.toolBarUse = value;
            }
        }
    }
}

